import warnings
from itertools import product
from concurrent.futures import ThreadPoolExecutor, as_completed

import numpy as np
import pandas as pd

import config
from trader import Trader
from market import Market
from amm import BaseAMM, LMSR, DPM, DPA
from sklearn.metrics import mean_absolute_error

warnings.filterwarnings("ignore")


def run(
        amm: BaseAMM,
        volatility: float,  # true选项发生的波动性
        trader_num: int,  # 交易者数量
        noisy_ratio: float,  # 噪声交易者比例
        noisy_degree: float  # 噪声交易者噪声水平
):
    if volatility == -1:
        probability = np.random.uniform(0, 0.5)
    else:
        probability = np.random.uniform(0, 1)

    market = Market(probability)  # 初始化市场
    traders = Trader.bulk_create(trader_num, noisy_ratio, noisy_degree)  # 初始化交易者列表
    prob = []
    pred = []

    for i in range(config.PERIOD_NUM):  # 遍历每个时间片
        if volatility == -1 and i == config.PERIOD_NUM / 2:
            probability += 0.5

        noisy_probability = np.random.normal(probability, volatility if volatility != -1 else 0.1)  # 更新true选项的含噪音正确概率

        for trader in traders:  # 遍历每个交易者
            amm.execute(noisy_probability, market, trader)  # 交易者根据AMM机制和市场情况进行交易并更新

        pred.append(amm.probability(market))
        prob.append(probability)

    return mean_absolute_error(pred, prob), 1 - np.abs(pred[-1] - prob[-1])


df = pd.DataFrame(
    columns=["AMM", "volatility", "trader_num", "noisy_ratio", "mean MAE", "mean ACC", "std MAE", "std ACC"]
)

for amm, volatility, trader_num, noisy_ratio in product(
        [LMSR(1), DPM(), DPA(5)],
        config.VOLATILITY,
        config.TREADER_NUM,
        config.NOISY_TREADER_RATIO
):
    print(f"AMM={amm.__class__.__name__},{volatility=},{trader_num=},{noisy_ratio=}", end=" ")
    MAEs = []
    ACCs = []
    with ThreadPoolExecutor(max_workers=300) as executor:
        futures = {
            executor.submit(run, amm, volatility, trader_num, noisy_ratio, 0.2)
            for _ in range(config.ROUND_NUM)
        }
        for future in as_completed(futures):
            try:
                result = future.result()
                MAE, ACC = result
                MAEs.append(MAE)
                ACCs.append(ACC)
            except Exception as exc:
                print(f'任务产生了异常: {exc}')
    print(
        f" mean MAE={round(np.mean(MAEs), 6)},"
        f" mean ACC={round(np.mean(ACCs), 6)},"
        f" std MAE={round(np.std(MAEs), 6)},"
        f" std ACC={round(np.std(ACCs), 6)}"
    )

    df.loc[len(df)] = [
        amm.__class__.__name__,
        volatility,
        trader_num,
        noisy_ratio,
        np.mean(MAEs),
        np.mean(ACCs),
        np.std(MAEs),
        np.std(ACCs)
    ]

df.to_excel("amm.xlsx")
